home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
jdos.asm
< prev
next >
Wrap
Assembly Source File
|
1989-03-18
|
31KB
|
1,027 lines
TITLE JDOS.ASM
;
COMMENT *
Purpose: Perform 'DOS' functions from within most programs.
Allows other programs to be executed then return to the interrupted
program.
Created: 11-MAR-1989 Richard B. Johnson
Modified:
12-MAR-1989 V1.01 Richard B. Johnson
Added sign-on screens using direct screen-writes.
Added DOS version check. DOS V2.## does not work correctly.
13-MAR-1989 V1.02 Richard B. Johnson
Added code to intercept interrupt vectors that the interrupted
program might be using. If the interrupted program was using
the timer-tick, the program would crash.
Changed reserved word "WIDTH" to label "@WIDTH". Would produce a
warning message under MASM but not under OPTASM.
14-MAR-1989 V1.03 Richard B. Johnson
Added code to save the default interrupt table during initialization
and use this default table during the spawned process. This should
prevent possible reentry problems if spawned programs spawn other
processes also.
14-MAR-1989 V1.04 Richard B. Johnson
Added code to save the state of four possible 8250 UARTS including
any enabled interrupts and the baud-rate. The UART status is restored
before returning to the interrupted program. This allows communi-
cations programs to be interrupted, other communications programs
executed with different baud-rates, etc., then the return to the
interrupted program without any errors.
14-MAR-1989 V1.05 Richard B. Johnson
Added code to mask off the interrupt controller immediately
upon return from the spawmed process. Some communications programs
were leaving "hot" interrupts when they exited!! Since not even the
stack is in a known place when the EXEC call returns, this could
cause a crash. Symptom = "divide by zero error".
16-MAR-1989 V1.06 Richard B. Johnson
Added code to search for the screen segment to accommodate COMPAQ
"compatibles" that ALWAYS have the screen segment at B800H without
regard for any standards.
16-MAR-1989 V1.07 Richard B. Johnson
Fixed bug in code that failed to restore the interrupt controller
mask after a return from the spawned process. No crashes were
reported, but it's possible that a crash could occur if a program
being executed failed to restore "hot" interrupt vectors when
it was aborted. This might happen if the program being executed
by the spawned process aborted because of a fatal error.
Notice: This program must be compiled as a '.COM' file!
MASM JDOS;
LINK JDOS;
EXE2BIN JDOS.EXE JDOS.COM
DEL JDOS.EXE
*
VERS STRUC
DB 'V1.07' ; Set version number here ONLY.
@VERS DB ' '
VERS ENDS
;
TRUE EQU -1 ; Set logicals
FALSE EQU NOT TRUE
TESTING EQU FALSE ; Debugging conditional
CR EQU 0DH
LF EQU 0AH
INT_CTL EQU 21H ; Interrupt controller mask addr.
INT_RES EQU 20H ; Interrupt controller reset addr.
NOS_EOI EQU 20H ; Non-specific end-of-interrupt
MS_DOS EQU 21H ; Operating system interrupt
VIDEO EQU 10H ; Video BIOS code interrupr
ENVIR EQU 2CH ; Address of environment segment
KB EQU 1024 ; One kb =
MEM EQU 32 ; Extra bytes of memory required
TICK1 EQU 08H ; Clock tick
TICK2 EQU 1CH ; User timer
SCR_LIN EQU 15 ; Line to start
@WIDTH EQU 28 ; Width of the box
HEIGHT EQU 6 ; Height of the box
COL_SCR EQU (80 - @WIDTH) / 2 ; Column to center
SCR_WRD EQU 80 ; Words per line on the screen
LOCUS EQU (SCR_LIN * SCR_WRD * 2) + (COL_SCR * 2)
;
IN8250 STRUC
LIN_CTR DB ? ; Line control register
DIVISOR DW ? ; Divisor
INT_CTR DB ? ; Interrupt control register
MOD_CTR DB ? ; Modem control register
IN8250 ENDS
;
; Possible UART base addresses
;
ADDR1 EQU 03F8H ; COM1
ADDR2 EQU 02F8H ; COM2
ADDR3 EQU 03E8H ; COM3
ADDR4 EQU 02E8H ; COM4
;
PSEG SEGMENT PARA PUBLIC 'CODE'
START EQU $
ASSUME CS:PSEG, DS:PSEG, ES:PSEG, SS:NOTHING
ORG 100H
MAIN PROC NEAR
JMP INIT
MAIN ENDP
;
; Write the string addressed by SI to a box on the screen.
;
SIGNON PROC NEAR
PUSH ES
MOV ES,WORD PTR [SCR_SEG] ; Pick up screen segment
MOV DI,LOCUS ; Where to start the box
MOV CX,HEIGHT ; Height of the box
BOX0: PUSH CX ; Save height
MOV AH,01110000B ; Reverse video
MOV CX,@WIDTH ; Width of the box
BOX1: LODSB ; Get LOGO byte
STOSW ; Write the word
LOOP BOX1 ; Continue
ADD DI,(SCR_WRD - @WIDTH ) * 2 ; For next line
POP CX ; Restore height
LOOP BOX0
POP ES ; Restore segment
RET
SIGNON ENDP
;
; This is the main clock interrupt entry point. We check to see if
; [EFLAG] has been set. If not, we continue to old vector. If it has
; been set, we check to see if the sub-process has already been spawned
; by looking at [SPAWN]. If the process has not been spawned, we check
; the interrupted program's CS. It must be below 640k and above our
; CS or else a sub-process is not created.
;
ENTRY PROC FAR
PUSH BP
MOV BP,SP ; Set up index
PUSH AX ; Save a register
PUSH DS ; Save segment
;
PUSH CS
POP DS ; DS = CS
;
CMP BYTE PTR [SPAWN],0 ; See if we spawned the process
JNZ BYPASS ; Yes, continue
CMP BYTE PTR [EFLAG],0 ; Check entry flag
JZ BYPASS ; We don't want to do it
;
; See what we interrupted. Must be between current CS and end of
; 640k for us to enter.
;
; BP = Pushed BP
; BP + 2 = IP
; BP + 4 = CS
; BP + 6 = FLAGS
MOV AX,CS ; Pick up our code-segment
CMP [BP+4],AX ; Compare with interrupted segment
JC BYPASS ; Not the code to interrupt
CMP [BP+4],9000H ; Check high limit
JNC BYPASS ; Not the code to interrupt
;
MOV BYTE PTR [SPAWN],0FFH ; Set flag
CALL @LOCAL ; Call the local routine
MOV BYTE PTR [SPAWN],0 ; Reset the flag
MOV BYTE PTR [EFLAG],0 ; Reset rentry flag.
;
BYPASS: POP DS ; Restore segment
POP AX ; Restore register
POP BP ; Restore index
JMP DWORD PTR CS:[OLD_CLK] ; Continue
ENTRY ENDP
;
; Keyboard interrupt extension. If the call is to check status, we
; ignore it and simply jump to the old interrupt vector. If the call
; is to receive a character, we make the call ourselves, them check
; the character. If the character is the one used to spawn the sub-
; process, we set the sub-process flag, [EFLAG]. Then we substitute
; a null character for the key-code and return.
;
LCL_KBD PROC FAR
CMP BYTE PTR CS:[SPAWN],0 ; Already in the spawned process?
JZ ASK ; No, Check the request
NOCHR: JMP DWORD PTR CS:[OLD_KBD] ; Continue
ASK: CMP AH,0 ; Do we want a character?
JNZ NOCHR ; No, checking status
PUSHF ; Dummy INT
CALL DWORD PTR CS:[OLD_KBD] ; Go get the character
CMP AX,2B1CH ; Character we want?
JNZ HOME ; Nope
PUSH BX ; Yes, beep
PUSH BP ; Is sometimes destroyed
MOV AX,0E07H ; Sound the bell
MOV BX,7 ; Normal attribute
INT VIDEO ; Video ROM BIOS
POP BP ; Restore registers
POP BX
MOV BYTE PTR CS:[EFLAG],0FFH ; ..and set the flag
MOV AX,0 ; Substitute
HOME: RET 2 ; Return to caller
LCL_KBD ENDP
;
; This is the local procedure to create a subprocess.
;
@LOCAL PROC NEAR
MOV AX,[BP+4] ; BP = pushed BP
; BP + 2 = IP
; BP + 4 = CS
; BP + 6 = FLAGS
MOV WORD PTR [CS_SAV],AX ; Save the caller's code-segment
CLI ; No interrupts
CLD ; Forwards
MOV WORD PTR [SS_SAV],SS ; Save segment
MOV WORD PTR [SP_SAV],SP ; Save pointer
MOV AX,CS ; Get our segment
MOV SS,AX ; Into stack segment
MOV SP,OFFSET STKTOP ; Set up new stack
STI ; Allow interrupts
PUSH BX ; Save all registers
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
MOV DS,AX ; Fix up segments
MOV ES,AX
;
MOV AL,NOS_EOI
OUT INT_RES,AL ; Reset hardware controller
;
CALL SAV_UAR ; Save UART parameters
CALL SAV_DIR ; Save the directory
CALL SAV_DTA ; Save data transfer area
CALL SAV_SCR ; Save screen data
CALL SAV_MEM ; Free up some memory
CALL CLR_SCR ; Clear the screen
CALL SAV_INT ; Save interrupt table
MOV BYTE PTR DS:[80H],0 ; Show no bytes typed
MOV WORD PTR [SP_NEW],SP ; Save stack
MOV DX,OFFSET COMMAND ; Point to COMMAND.COM
MOV BX,OFFSET BLOCK ; Parameter block for the load
MOV AX,4B00H ; Load/execute program
INT MS_DOS ; Doit-toit
CLI ; Quiet while I fix
MOV AL,10011101B ; Mask off all but required interrupts
; ||||||||_________ Timer
; |||||||__________ Keyboard
; ||||||___________ Reserved
; |||||____________ Async (2)
; ||||_____________ Async (1)
; |||______________ Hard drive
; ||_______________ Floppy drive
; |________________ Printer
;
OUT INT_CTL,AL ; The interrupt controller
MOV AX,CS ; Restore all segments
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV SP,WORD PTR [SP_NEW] ; Restore stack
STI ; Allow interrupts
CLD ; Could be messed up
;
JNC GOOD
MOV SI,OFFSET ERROR1 ; Point to string
CALL PROMPT ; Display to console
MOV AH,0 ; Get response
PUSHF
CALL DWORD PTR [OLD_KBD] ; Wait for a response
;
GOOD: CALL RES_DIR ; Restore the directory
CALL RES_DTA ; Restore data transfer area
CALL RES_MEM ; Re-acquire the memory we used
CALL RES_SCR ; Restore screen
CALL RES_INT ; Restore interrupt table
CALL RES_UAR ; Restore UART parameters.
POP ES ; Restore all registers
POP DI
POP SI
POP DX
POP CX
POP BX
CLI
MOV SS,WORD PTR [SS_SAV]
MOV SP,WORD PTR [SP_SAV]
STI
RET
@LOCAL ENDP
;
; Free up memory. Save memory contents in file VIRTUAL.MEM.
;
SAV_MEM PROC NEAR
MOV DX,OFFSET VIRMEM ; Point to code-data filename
MOV AX,3C00H ; Create file function
XOR CH,CH ; File attributes
MOV CL,00000110B ; Hidden/system
INT MS_DOS ; Create the file
JNC W1 ; Good create
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR5 ; Point to 'create'
JMP SHO_ERR ; Show the error, implied return
;
W1: MOV BX,AX ; File handle
PUSH DS ; Save segment
MOV DS,WORD PTR [CS_SAV] ; Pick up code segment
WR_ALL: MOV AX,4000H ; Write to file
MOV CX,0FFFFH ; 64k -1
XOR DX,DX ; Offset 0
INT MS_DOS ; Write the file
CMP AX,CX ; Write as requested?
JNZ WR_OK ; Exit, bad write
MOV AX,DS ; Pick up segment
ADD AX,1000H ; Next segment
MOV DS,AX ; Index 64k
CMP AX,0A000H ; Check limit
JC WR_ALL ; Continue
WR_OK: POP DS ; Restore segment
JNC W2 ; Good write
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR6 ; Point to 'write'
JMP SHO_ERR ; Show the error, implied return
;
W2: MOV AX,3E00H ; Close file handle
INT MS_DOS
JNC W3 ; Good close
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR7 ; Point to 'close'
JMP SHO_ERR ; Show the error, implied return
;
W3: MOV BX,(100H SHR 4) ; Release all memory above 100H
PUSH ES ; Save segment
MOV ES,WORD PTR [CS_SAV] ; Caller's code-segment
MOV AX,4A00H ; Modify memory
INT MS_DOS
POP ES ; Restore segment
IF TESTING
JNC MEM1
;
MOV SI,OFFSET ERROR2 ; Point to memory error message.
CALL PROMPT ; Desplay on the screen
MOV AH,0
PUSHF
CALL DWORD PTR [OLD_KBD] ; Wait for a response
ENDIF
MEM1: RET
SAV_MEM ENDP
;
; Acquire memory. Restore it's contents from file VIRTUAL.MEM.
;
RES_MEM PROC NEAR
MOV BX,0FFFFH ; Get everything back.
MOV AX,4A00H ; Modify memory
PUSH ES
MOV ES,WORD PTR [CS_SAV] ; Pick up code segment
INT MS_DOS
POP ES
;
MOV DX,OFFSET VIRMEM ; Point to code-data filename
MOV AX,3D00H ; Open file for reading
XOR CX,CX ; File attributes
INT MS_DOS ; Open the file
JNC Z1 ; Good open
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR8 ; Point to 'open'
JMP SHO_ERR ; Show error, implied return
;
Z1: PUSH DS ; Save segment
MOV DS,WORD PTR [CS_SAV] ; Pick up code segment
MOV BX,AX ; File handle
RD_ALL: MOV CX,0FFFFH ; 64k -1
XOR DX,DX ; Offset 0
MOV AX,3F00H ; Read from file
INT MS_DOS ; Write the file
JC RD_DON ; Bad read
CMP CX,AX ; See if end of file
JNZ RD_DON ; No more bytes, all done
MOV AX,DS ; Pick up segment
ADD AX,1000H ; Next 64k block
MOV DS,AX ; Update segment
JMP SHORT RD_ALL ; Continue
RD_DON: POP DS ; Restore segment
JNC Z2
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR9 ; Point to 'read'
JMP SHO_ERR ; Show error, implied return
;
Z2: MOV AX,3E00H ; Close file handle
INT MS_DOS
JNC Z3 ; Good close
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR7 ; Point to 'close'
JMP SHO_ERR ; Show error, implied return
;
Z3: MOV DX,OFFSET VIRMEM ; Point to code-data filename
MOV AX,4100H ; Delete the file
INT MS_DOS
JNC Z4 ; Good delete
MOV DX,OFFSET VIRMEM ; Point to filename
MOV SI,OFFSET ERROR10 ; Point to 'delete'
JMP SHO_ERR ; Show error, implied return
;
Z4: RET
RES_MEM ENDP
;
; Restore the DTA
;
RES_DTA PROC NEAR
PUSH DS ; Save segment
LDS DX,DWORD PTR [DTA] ; Get old DTA address
MOV AX,1A00H ; Set DTA address
INT MS_DOS
POP DS ; Restore segment
RET
RES_DTA ENDP
;
; Save the DTA
;
SAV_DTA PROC NEAR
PUSH ES ; Save segment
MOV AX,2F00H ; Get DTA address
INT MS_DOS
MOV WORD PTR [DTA_OFF],BX ; Save current DTA address
MOV WORD PTR [DTA_SEG],ES
POP ES ; Restore segment.
RET
SAV_DTA ENDP
;
; Save the interrupt table.
;
SAV_INT PROC NEAR
IN AL,INT_CTL ; Get interrupt controller mask
MOV BYTE PTR [OLD_MSK],AL ; Save the mask
OR AL,00011100B ; Reset IRQ3, IRQ4, Reserved
OUT INT_CTL,AL ; Set the mask
;
; Save present interrupt vectors.
;
XOR AX,AX ; Get a zero
MOV SI,AX ; Offset zero
MOV CX,KB ; 1k to move
;
PUSH DS
MOV DS,AX ; Point to interrupt table
MOV DI,OFFSET TABLE ; Point to our data-space
CLI
REP MOVSB ; Copy to our CS
STI
POP DS ; Restore segment
;
; Set the default interrupt vectors.
;
XOR AX,AX
MOV DI,AX ; Offset zero
MOV SI,OFFSET DEFAULT ; Where the interrupt data is
MOV CX,KB ; 1k to replace
;
PUSH ES ; Save the segment
MOV ES,AX ; Zero the segment
CLI
REP MOVSB
STI
POP ES ; Restore segment
RET
SAV_INT ENDP
;
; Restore the interrupt table
;
RES_INT PROC NEAR
XOR AX,AX
MOV DI,AX ; Offset zero
MOV SI,OFFSET TABLE ; Where the interrupt data is
MOV CX,KB ; 1k to replace
;
PUSH ES ; Save the segment
MOV ES,AX ; Zero the segment
CLI
REP MOVSB
STI
POP ES ; Restore segment
;
MOV AL,BYTE PTR [OLD_MSK] ; Get old controller mask
OUT INT_CTL,AL ; Set interrupt controller mask
RET
RES_INT ENDP
;
; Clear the screen, write message.
;
CLR_SCR PROC NEAR
MOV AL,BYTE PTR [SCR_MOD] ; Get screen mode byte
MOV AH,0 ; Set mode function
INT VIDEO ; That should clear the screen
MOV SI,OFFSET LOGO2 ; Point to 'EXIT' message
CALL SIGNON ; Print to screen
RET
CLR_SCR ENDP
;
; Save the default directory.
;
SAV_DIR PROC NEAR
MOV AH,47H ; Get current directory function
XOR DL,DL ; Get default
MOV SI,OFFSET CUR_DIR ; Where to copy the string
INT MS_DOS ; Put it there
MOV AH,19H ; Get current disk
INT MS_DOS ; From DOS
ADD AL,'A' ; Drive bias
MOV BYTE PTR [DRV],AL ; Put in drive specifier
RET
SAV_DIR ENDP
;
SAV_SCR PROC NEAR
MOV AH,15 ; Return video state
INT VIDEO ; Video BIOS
MOV BYTE PTR [SCR_MOD],AL ; Current mode
MOV BYTE PTR [SCR_COL],AH ; Number of columns
MOV BYTE PTR [SCR_PAG],BH ; Current page
;
MOV AH,3 ; Get cursor position
INT VIDEO ; Video BIOS
MOV WORD PTR [CUR_POS],DX ; Save cursor position
MOV WORD PTR [CUR_TYP],CX ; Save cursor type
;
MOV DX,OFFSET SCREEN ; Point to screen-data filename
MOV AX,3C00H ; Create file function
XOR CH,CH ; File attributes
MOV CL,00000110B ; Hidden/system
INT MS_DOS ; Create the file
JNC Y1 ; Good create
MOV DX,OFFSET SCREEN ; Point to filename
MOV SI,OFFSET ERROR5 ; Point to 'create'
JMP SHO_ERR ; Show error, implied return
;
Y1: MOV BX,AX ; File handle
MOV CX,0FFFFH ; 64k -1
XOR DX,DX ; Offset zero
MOV AX,4000H ; Write to file
PUSH DS ; Save segment
MOV DS,WORD PTR [SCR_SEG] ; Pick up screen segment
INT MS_DOS ; Write the file
POP DS ; Restore segment
JNC Y2 ; Good write
MOV DX,OFFSET SCREEN ; Point to filename
MOV SI,OFFSET ERROR6 ; Point to 'write'
JMP SHO_ERR ; Show error, implied return
;
Y2: MOV AX,3E00H ; Close file handle
INT MS_DOS
JNC Y3 ; Good close
MOV DX,OFFSET SCREEN ; Point to filename
MOV SI,OFFSET ERROR7 ; Point to 'close'
JMP SHO_ERR ; Show error, implied return
Y3: RET
SAV_SCR ENDP
;
; Restore the default directory.
;
RES_DIR PROC NEAR
MOV AH,0EH ; Change drive function
MOV DL,BYTE PTR [DRV] ; Get saved drive letter
SUB DL,'A' ; Remove bias
INT MS_DOS ; Go do it
;
MOV AH,3BH ; Change directory function
MOV DX,OFFSET DRV ; Full drive/path name
INT MS_DOS
RET
RES_DIR ENDP
;
RES_SCR PROC NEAR
MOV DX,OFFSET SCREEN ; Point to screen-data filename
MOV AX,3D00H ; Open file for reading
XOR CX,CX ; File attributes
INT MS_DOS ; Open the file
JNC X1 ; Good open
MOV DX,OFFSET SCREEN ; Filename
MOV SI,OFFSET ERROR8 ; Point to 'open'
JMP SHO_ERR ; Show the error, Implied return
;
X1: MOV BX,AX ; File handle
MOV CX,0FFFFH ; 64k -1
XOR DX,DX ; Offset zero
MOV AX,3F00H ; Read from file
PUSH DS ; Save segment
MOV DS,WORD PTR [SCR_SEG] ; Pick up screen segment
INT MS_DOS ; Write the file
POP DS ; Restore segment
JNC X2 ; Good read
MOV DX,OFFSET SCREEN ; Filename
MOV SI,OFFSET ERROR9 ; Point to 'read'
JMP SHO_ERR ; Implied return
;
X2: MOV AX,3E00H ; Close file handle
INT MS_DOS
JNC X3 ; Good close
MOV DX,OFFSET SCREEN ; Filename
MOV SI,OFFSET ERROR7 ; Point to 'close'
JMP SHO_ERR ; Implied return
;
X3: MOV DX,OFFSET SCREEN ; Point to screen-data filename
MOV AX,4100H ; Delete the file
INT MS_DOS
JNC X4 ; Good delete
MOV DX,OFFSET SCREEN ; Filename
MOV SI,OFFSET ERROR10 ; Point to 'delete'
JMP SHO_ERR ; Implied return
;
X4: MOV AH,5 ; Select active page
MOV AL,BYTE PTR [SCR_PAG] ; Get previous screen page
INT VIDEO ; Video BIOS
;
MOV AH,1 ; Set cursor type
MOV CX,WORD PTR [CUR_TYP] ; Get previous cursor type
INT VIDEO ; Video BIOS
;
MOV AH,2 ; Set cursor position
MOV BH,BYTE PTR [SCR_PAG] ; Page number.
MOV DX,WORD PTR [CUR_POS] ; Get saved cursor position
INT VIDEO ; Video ROM BIOS
RET
RES_SCR ENDP
;
PROMPT PROC NEAR
LODSB ; Get memory byte
TEST AL,AL ; Check for a null
JZ PEXIT ; All done
MOV BX,7 ; Page zero/normal attribute
MOV AH,14 ; Dumb terminal mode
INT VIDEO ; Video BIOS
JMP SHORT PROMPT ; Continue
PEXIT: RET
PROMPT ENDP
;
; Upon entry, DX points to filename. Si points to string for open/close
; etc. The error message is printed to the screen.
;
SHO_ERR PROC NEAR
PUSH SI
MOV SI,OFFSET ERROR4 ; Point to "Can't"
CALL PROMPT ; Write to screen
POP SI ; Point to create/write/read, etc
CALL PROMPT ; Write to screen
MOV SI,OFFSET ERROR11 ; Point to "file"
CALL PROMPT ; Write to screen
MOV SI,DX ; Get file name
JMP PROMPT ; Write to screen, implied return.
SHO_ERR ENDP
;
; Save UART parameters.
;
SAV_UAR PROC NEAR
MOV DI,OFFSET UAR_PAR ; Point to Uart parameter table
MOV DX,ADDR1 ; Pick up address of UART
CALL GET_PAR ; Get UART parameters
MOV DX,ADDR2 ; Pick up address of UART
CALL GET_PAR ; Get UART parameters
MOV DX,ADDR3 ; Pick up address of UART
CALL GET_PAR ; Get UART parameters
MOV DX,ADDR4 ; Pick up address of UART
CALL GET_PAR ; Get UART parameters
RET
SAV_UAR ENDP
;
; Get UART parameters. UART base-port is in DX. Storage for
; parameters is pointed to by DI. After saving parameters, disable
; any interrupt enable bits.
;
GET_PAR PROC NEAR
ADD DX,3 ; Offset to line control register
IN AL,DX ; Get line control bits
MOV BL,AL ; Save the bits
STOSB ; Save in memory
OR AL,10000000B ; Divisor access bit
OUT DX,AL ; Set divisor access bit
SUB DX,3 ; Back to base port
IN AX,DX ; Get divisor
STOSW ; Save in memory
ADD DX,3 ; Offset to line control register
MOV AL,BL ; Get saved line-control bits
OUT DX,AL ; Reset divisor latch
SUB DX,2 ; Set to interrupt control register
IN AL,DX ; Get the control bits
STOSB ; Save in memory
XOR AL,AL ; Turn off interrupt control
OUT DX,AL ; Reset the bits
ADD DX,3 ; Offset to modem control
IN AL,DX ; Save modem control bits
STOSB ; Save in memory
MOV CX,6 ; Registers to read
SUB DX,4 ; Back to base port
RDALL1: IN AL,DX ; Read port
INC DX ; Ready next
LOOP RDALL1 ; Read all ports
MOV AL,NOS_EOI ; Non-specific end-of-interrupt
OUT INT_RES,AL ; Reset hardware controller.
RET
GET_PAR ENDP
;
; Restore UART parameters.
;
RES_UAR PROC NEAR
MOV SI,OFFSET UAR_PAR ; Point to Uart parameter table
MOV DX,ADDR1 ; Pick up address of UART
CALL SET_PAR ; Set UART parameters
MOV DX,ADDR2 ; Pick up address of UART
CALL SET_PAR ; Set UART parameters
MOV DX,ADDR3 ; Pick up address of UART
CALL SET_PAR ; Set UART parameters
MOV DX,ADDR4 ; Pick up address of UART
CALL SET_PAR ; Set UART parameters
RET
RES_UAR ENDP
;
; Set UART parameters. UART base-port is in DX. Storage for
; parameters is pointed to by SI.
;
SET_PAR PROC NEAR
ADD DX,3 ; Line control register
IN AL,DX ; Get present control-bits
OR AL,10000000B ; Set divisor latch access bit
OUT DX,AL ; To line-control register
LODSB ; Get old line-control bits
MOV BL,AL ; Save for now
SUB DX,3 ; Back to the base register
LODSW ; Get saved divisor
OUT DX,AX ; Out the adjacent ports
ADD DX,3 ; Back to line-control
MOV AL,BL ; Get saved control-bits
AND AL,01111111B ; Verify DLAB is reset
OUT DX,AL ; Restore line-control
SUB DX,2 ; Set to interrupt control register
LODSB ; Get old bits
OUT DX,AL ; Restore
ADD DX,3 ; Offset to modem control
LODSB ; Get old bits
OUT DX,AL ; Restore
MOV CX,6 ; Registers to read
SUB DX,4 ; Back to base port
RDALL2: IN AL,DX ; Read port
INC DX ; Ready next
LOOP RDALL2 ; Read all ports
MOV AL,NOS_EOI ; Non-specific end-of-interrupt
OUT INT_RES,AL ; Reset hardware controller.
RET
SET_PAR ENDP
;
ERROR1 DB CR,LF,'Can''t load the command processor! <CR> ',0
ERROR2 DB CR,LF,'Can''t release memory! <CR> ',0
ERROR4 DB CR,LF,'Can''t ',0
ERROR5 DB 'create',0
ERROR6 DB 'write',0
ERROR7 DB 'close',0
ERROR8 DB 'open',0
ERROR9 DB 'read',0
ERROR10 DB 'delete',0
ERROR11 DB ' file ',0
OLD_MSK DB ? ; Old interrupt mask.
SPAWN DB 0 ; Flag for spawned sub-process
EFLAG DB 0 ; Entry flag
SCR_MOD DB ? ; Screen mode
SCR_PAG DB ? ; Screen page
SCR_COL DB ? ; Columns on screen
CS_SAV DW ? ; Interrupted program's CS
SP_SAV DW ? ; Interrupted program's SP
SS_SAV DW ? ; Interrupted program's SS
SP_NEW DW ? ; Save SP for EXEC call
SCR_SEG DW 0B000H ; Segment of screen regen buffer
CUR_TYP DW ? ; Cursor type
CUR_POS DW ? ; Cursor position
DTA LABEL DWORD ; Data transfer area
DTA_OFF DW ? ; Offset
DTA_SEG DW ? ; Segment
OLD_KBD LABEL DWORD ; Old keyboard vector
KBD_OFF DW ? ; Offset
KBD_SEG DW ? ; Segment
OLD_CLK LABEL DWORD ; Old clock vector
CLK_OFF DW ? ; Offset
CLK_SEG DW ? ; Segment
;
COMSPEC DB 'COMSPEC=' ; Environment search string
COMLEN EQU $ - COMSPEC ; It's length
COMMAND DB 65 DUP (0) ; To copy command processor name
DRV DB '?:\' ; Current directory drive and root.
CUR_DIR DB 65 DUP (0) ; Rest of the current directory string
SCREEN DB '\SCREEN.$$$',0 ; Screen data file.
VIRMEM DB '\VIRTUAL.MEM',0 ; Virtual memory file
;
; Parameter block for EXEC function call
;
BLOCK DW 0 ; Use current environment
DW 80H ; Offset of command line
CS0 DW ? ; Segment of command line
DW 5CH ; Offset of FCB #1
CS1 DW ? ; Segment of FCB #1
DW 6CH ; Offset of FCB #2
CS2 DW ? ; Segment of FCB #2
;
UAR_PAR LABEL BYTE ; Where the UART parameters are kept.
IN8250 <>
IN8250 <>
IN8250 <>
IN8250 <>
;
LOGO2 DB 28 DUP (' ')
STRTL2 DB (28 - ( @VERS + 4 ) ) / 2 DUP (' ')
DB 'JDOS '
VERS <>
ENDL2 EQU $ - STRTL2
DB 28 - ENDL2 DUP (' ')
DB ' Resident Command Processor '
DB ' ACTIVE '
DB ' Type EXIT ─┘ to return '
DB 28 DUP (' ')
;
; Put on a paragraph boundary.
;
ORG (( ($-START) + 16) AND 1111111111110000B)
DB 32 DUP ('STACK ')
;
STKTOP LABEL WORD
DEFAULT LABEL BYTE ; For our default interrupt table
ORG $ + KB
BUFFER LABEL BYTE ; Misc buffer for environment parse
TABLE LABEL BYTE ; Saved interrupt table during spawn
ORG $ + KB
TOP EQU $
;
INIT PROC NEAR
MOV AX,3000H ; Get DOS version number
INT MS_DOS ; From DOS
CMP AL,3 ; Need verion 3+
JNC VERSOK ; Its okay
MOV SI,OFFSET ERROR12 ; Point to version error
EXITF: CALL PROMPT ; Write to screen, exit fatal
MOV AX,4C01H ; Exit, ERRORLEVEL 1
INT MS_DOS ; To DOS
;
VERSOK: INT 11H ; Equipment check
AND AL,00110000B ; Mask everything but video info
CMP AL,00100000B ; See if color
JNZ DEFULT ; Default is mono
MOV WORD PTR [SCR_SEG],0B800H ; Color screen segment
DEFULT: CALL CHK_SEG ; See if its writable memory
JZ SCR_OK ; Found writable memory
MOV WORD PTR [SCR_SEG],(0B000H - 100H); Start at lowest segment
SERCH0: ADD WORD PTR [SCR_SEG],00100H ; Incr screen segment
CMP WORD PTR [SCR_SEG],0E000H ; Upper limit of search
JC SERCH1 ; Not outside limits
MOV SI,OFFSET ERROR13 ; Point to "can't find screen"
JMP SHORT EXITF ; Write to screen and exit fatal
SERCH1: CALL CHK_SEG ; Check for writable memory
JNZ SERCH0 ; Keep looking
;
SCR_OK: CALL GET_CMD ; Get command processor
JNC INIT2 ; Found
MOV SI,OFFSET ERROR1 ; Point to error message
JMP SHORT EXITF ; Write to screen and exit fatal
;
INIT2: MOV WORD PTR [CS0],CS ; Fix up parameter block
MOV WORD PTR [CS1],CS
MOV WORD PTR [CS2],CS
MOV AH,35H ; Get vector function
MOV AL,TICK1 ; Clock tick
INT MS_DOS ; Go get it
MOV WORD PTR [CLK_OFF],BX ; Save the vector
MOV WORD PTR [CLK_SEG],ES
;
MOV AH,35H ; Get vector function
MOV AL,16H ; Kbd interrupt
INT MS_DOS ; Get the vector
MOV WORD PTR [KBD_OFF],BX ; Save the vector
MOV WORD PTR [KBD_SEG],ES
;
MOV DI,BX ; ES:DI = old vector
MOV SI,OFFSET LCL_KBD ; DS:SI = new vector
MOV CX,10H ; Check 16 bytes
REPZ CMPSB
PUSH CS
POP ES ; restore segment
JNZ NEW ; Never installed before
;
MOV SI,OFFSET ERROR3 ; Point to error message
CALL PROMPT ; Display to console
MOV AX,4C00H ; Exit to DOS ERRORLEVEL 0
INT MS_DOS
;
NEW: MOV AH,25H ; Set vector function
MOV AL,TICK1 ; Vector to set
MOV DX,OFFSET ENTRY ; Vector to patch
INT MS_DOS ; Patch the vector
;
MOV AH,25H ; Set vector function
MOV AL,16H ; Vector to set
MOV DX,OFFSET LCL_KBD ; Vector to patch
INT MS_DOS ; Patch the vector
;
PUSH ES ; Save segment
MOV ES,WORD PTR DS:[ENVIR] ; Get environment segment
XOR BX,BX ; Free it all up
MOV AX,4A00H ; Modify memory
INT MS_DOS ; Call DOS
POP ES ; Restore segment
;
; Save our default interrupt table.
;
XOR AX,AX ; Get a zero
MOV SI,AX ; Offset zero
MOV CX,KB ; 1k to move
;
PUSH DS
MOV DS,AX ; Point to interrupt table
MOV DI,OFFSET DEFAULT ; Point to our data-space
CLI
REP MOVSB ; Copy to our CS
STI
POP DS ; Restore segment
;
MOV SI,OFFSET LOGO1 ; Point to 'installed' logo
CALL SIGNON ; Signon the message.
MOV AX,3100H ; Keep process
MOV DX,OFFSET TOP ; Last location to keep
ADD DX,MEM ; Memory we need
SHR DX,1 ; Div/2
SHR DX,1 ; Div/4
SHR DX,1 ; Div/8
SHR DX,1 ; Div/16
INT MS_DOS ; Exit to DOS
JMP $ ; For fatal error abort
INIT ENDP
;
; Check screen segment for writable memory.
;
CHK_SEG PROC NEAR
PUSH DS ; Save segment
MOV DS,WORD PTR [SCR_SEG] ; Get screen segment
MOV AX,WORD PTR DS:[0] ; Get word at address zero
MOV BX,AX ; Save memory word
NOT AX ; Invert
NOT WORD PTR DS:[0] ; Invert memory word
CMP AX,WORD PTR DS:[0] ; See if it went
MOV WORD PTR DS:[0],BX ; Put original word back
POP DS ; Restore segment
RET
CHK_SEG ENDP
;
; Get boot command interpreter. Find out where COMMAND.COM is.
;
GET_CMD PROC NEAR
XOR SI,SI ; Offset zero
MOV DI,OFFSET BUFFER ; Where to copy the string
MOV AX,WORD PTR DS:[ENVIR] ; Get environment segment
PUSH DS ; Save segment
MOV DS,AX ; Set environment segment
GET0: LODSB ; Get environment byte
TEST AL,AL ; Check for a null
JNZ GET1 ; Not a null
CMP BYTE PTR [SI],0 ; Next on a null too?
JZ GET3 ; Yes, all done
GET1: CMP AL,'z' ; Check limits
JA GET2 ; Not lower case
CMP AL,'a' ; Check lower limit
JB GET2 ; Not lower case
AND AL,95 ; Reset lower-case bits
GET2: STOSB ; Save byte
JMP SHORT GET0 ; Continue until the double-null
GET3: STOSB ; Final null
POP DS ; Restore segment
;
MOV CX,DI ; Get last pointer
SUB CX,OFFSET BUFFER ; CX= length of environment strings
MOV BX,OFFSET COMSPEC ; Substring to find
MOV DX,COMLEN ; Length of the substring
MOV SI,OFFSET BUFFER ; Where the string should be found.
CALL COMPARE ; Scan the string
JNZ GET10 ; Not found
MOV DI,OFFSET COMMAND ; Where to copy COMMAND.COM
MOV BX,SI ; Save location
GET4: LODSB ; Get byte to transfer
TEST AL,AL ; Check for terminator
JZ GET5 ; String is transferred
STOSB ; Copy byte
JMP SHORT GET4 ; Continue
GET5: RET ; No errors
GET10: STC ; Show error
RET
GET_CMD ENDP
;
; Compares the substring addressed by DS:BX to the string addressed
; by DS:SI. DX contains the substring length. CX contains the string
; length. Returns ZF=TRUE if the string is found. SI points to one
; character after the string if its found.
;
COMPARE PROC NEAR
PUSH CX ; Save string length
COMP0: PUSH CX ; Save original string length
MOV CX,DX ; Get substring length
MOV DI,BX ; Get substring location
REPZ CMPSB ; Compare string/substring
POP CX ; Restore string length
JZ FOUND ; String was found
LOOP COMP0 ; Not found, continue
INC CX ; Make NZ
FOUND: POP CX ; Restore string length
RET
COMPARE ENDP
;
ERROR3 DB CR,LF,'JDOS is already installed!',CR,LF,0
ERROR12 DB CR,LF,'Need DOS version 3.0 or higher to execute!',CR,LF,0
ERROR13 DB CR,LF,'Can''t find writable screen memory!',CR,LF,0
LOGO1 DB 28 DUP (' ')
STRTL DB (28 - ( @VERS + 4 ) ) / 2 DUP (' ')
DB 'JDOS '
VERS <>
ENDL EQU $ - STRTL
DB 28 - ENDL DUP (' ')
DB ' Resident Command Processor '
DB ' '
DB ' Use ^\ to activate. '
DB 28 DUP (' ')
PSEG ENDS
END MAIN